#pragma once
#ifndef _AS_SERVICE_H_
#define _AS_SERVICE_H_

#include <thread>
#include <optional>
#include <array>
#include "object_pool.h"
#include "net_include.h"
#include "as_session.h"

#ifdef _WIN32
#include <minwinbase.h>
#include <MSWSock.h>
#endif

namespace as
{
namespace inet
{
class AsSessionMgr;

class AS_DLL AsAcceptor
{
public:
    AsAcceptor();
    ~AsAcceptor();

public:
    AsAcceptor* set_workthread_num(int num = 1);

    AsAcceptor* start(NetAddr &addr);
    AsAcceptor* start(std::string_view ip);
    AsAcceptor* start(std::string_view host, int port);
    void register_sys_fun();
    void create_io_and_post_event();
    void stop();

    AsAcceptor* set_new_conn_cb(new_conn_cb cb)
    {
        m_new_con_cb = std::move(cb);
        return this;
    }

    AsAcceptor* set_recv_cb(recv_cb cb)
    {
       m_recv_cb = std::move(cb); 
       return this;
    }

    AsAcceptor* set_write_cb(write_cb cb)
    {
        m_write_cb = std::move(cb);
        return this;
    }

    AsAcceptor* set_close_cb(close_cb cb)
    {
        m_close_cb = std::move(cb);
        return this;
    }

#ifdef _WIN32
    //post iocp event
    int DoWinAccept(IOContext *io);
#else
    int DoUnixAccept(IOContext *io);
#endif

    bool post_accept(IOContext *io);
    bool post_recv(IOContext *io);
    bool post_write(IOContext *io);

    //do io
    int DoAccept(IOContext *io);
    int DoRecv(IOContext *io, int byteNum);
    int DoWrite(IOContext *io, int byteNum);

    void work_run();
    void run();

    static void signal_fun(int sig);
    static void RegSignal(int sig, const std::function<void()> cb_fun);
protected:
    IOContext* pop_io_context(socket_fd fd);
    void push_io_context(IOContext *io);

private:
    io_state m_state = io_state::NONE;

    //work thread
    std::vector<std::thread> m_workThreads;
    int m_workThreadNum = 10;

    //io event
    std::array<IOContext, SVC_MAX_EVENT_NUM> m_events = {};

#ifdef _WIN32
    //complate port
    HANDLE m_ioPort;

    // load dll function
    static LPFN_ACCEPTEX m_accept_fun;
    static LPFN_GETACCEPTEXSOCKADDRS m_accept_addr_fun;
#else
    //epoll port
    int m_ioPort;
#endif
    //listen socket
    std::unique_ptr<as::inet::AsSession> m_listenSocket;

    //check event is dirty
    std::atomic<bool> m_eventFlags;

    //user callback
    new_conn_cb m_new_con_cb;
    recv_cb m_recv_cb;
    write_cb m_write_cb;
    close_cb m_close_cb;


    static std::map<int, std::function<void()> > m_signal_map;

};


}
}

#endif